#if !defined(PROGRESS_INDICATOR_H)
#define PROGRESS_INDICATOR_H
#include <iostream>
#include "portable_timer.h"
//#include "debug_func.h"
#include <cassert>
using std::ostream;
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

//	t_progress_indicator

//		streams out progress dots every n iterations

//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
class t_progress_indicator
{
	unsigned			every;
	ostream&			os;
	unsigned			iteration;
	unsigned			line_length;
	unsigned			limit;
	unsigned			count_dots;
	char				indicator;
	bool				using_timer;
	double				elapsed_time;
	t_portable_timer	timer;
public:
	t_progress_indicator(ostream& os_, unsigned every_, char indicator_ = '.',
							unsigned line_length_ = 50):
		every(every_), os(os_), iteration(0),
		line_length(line_length_), limit(0), count_dots(0), indicator(indicator_),
		using_timer(false), elapsed_time(0.0)
	{
		assert(line_length);
		if (!every)
			every++;
	}
	t_progress_indicator(ostream& os_, unsigned every_, unsigned limit_,
							char indicator_ = '.', unsigned line_length_ = 50):
		every(every_), os(os_), iteration(0),
		line_length(line_length_), limit(limit_), count_dots(0), indicator(indicator_),
		using_timer(false), elapsed_time(0.0)
	{
		assert(line_length);
		if (!every)
			every++;
	}
	void use_timer() {using_timer = true;}
	void finish()
	{
		// only print brackets if made progress (ie. some dots were printed)
		if (count_dots)
		{
			os << "]";
			if (using_timer)
			{
				// if line_length = 50, count_dots = 50 then
				assert(line_length - ((count_dots - 1) % line_length) > 0);
				os	<< std::string(line_length - ((count_dots - 1) % line_length), ' ');
				elapsed_time += timer.reset();
				os << timer.pretty_time(elapsed_time) << "   altogether.";
			}
			os << std::endl;
		}
		count_dots = 0;
		iteration = 0;
	}
	~t_progress_indicator()
	{
		// print closing bracket
		finish();
	}
	
	void print_indicator(const std::string& str)
	{
		for (unsigned i = 0; i < str.length(); ++i)
			print_indicator(str[i]);
	}
	
	void print_indicator(char c)
	{
		// print opening bracket if this is the first increment
		if (!count_dots)
		{		
			os << "\t[";
			os.flush();
			timer.reset();
		}

		// wrap around if necessary
		if (count_dots && count_dots % line_length == 0)
		{
			if (using_timer)
			{
				if (!limit)
				{
					os << "  " << timer.pretty_reset();
				}
				else
				{
					elapsed_time += timer.reset();
					double forecast_time = elapsed_time * limit / iteration;
					os << "  " << timer.pretty_time(elapsed_time)
						<< " ( out of " << timer.pretty_time(forecast_time) << ")";
				}
			}
			os << "\n\t ";
		}

		++count_dots;
		os << c;
		os.flush();
	}
	unsigned value(){return iteration;}
	bool iterating() {return iteration < limit;}
	void increment()
	{
		assert(every);
		if (++iteration % every == 0)
			print_indicator(indicator);
	}
	void operator++()
	{
		increment();
	}
	void operator++(int)
	{
		increment();
	}
};
#endif	// PROGRESS_INDICATOR_H
